package server.tool;


import cn.hutool.bloomfilter.BitMapBloomFilter;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.StrUtil;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Scope;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Component
@SuppressWarnings("all")
@Scope(value = "singleton")
public class RedisTool {
    @Resource
    private Tool tool;


    @Resource
    private StringRedisTemplate str_temp;
    private ValueOperations<String, String> str_ops = null;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    private HashOperations<String, Object, Object> kv_ops = null;

    private BitMapBloomFilter filter = new BitMapBloomFilter(10);

    @PostConstruct
    public void set_ops() {
        Optional.ofNullable(str_temp).ifPresent(t -> {
            str_ops = str_temp.opsForValue();
        });
        Optional.ofNullable(redisTemplate).ifPresent(t -> {
            kv_ops = t.opsForHash();
        });
        set_filter();
    }

    protected boolean is_empty() {
        return str_temp == null;
    }

    public Boolean hasKey(String key) {
        return str_temp.hasKey(key);
    }

    public Boolean save_string(String key, String content) {
        if (is_empty()) {
            return false;
        }
        set_filter();
        Boolean commit;
        try {
            str_ops.set(key, content);
            commit = str_temp.hasKey(key);
        } catch (NullPointerException n) {
            Console.log("空指针异常", n);
            commit = false;
        }
        return commit;
    }

    /**
     * @param key     关键字
     * @param content 字符串文本
     * @param time    过期时间 TimeUnit
     * @return bool
     */
    public Boolean save_string(String key, String content, long time, TimeUnit unit) {
        set_filter();
        if (StrUtil.isAllNotEmpty(key, content)) {
            str_temp.expire(key, time, unit);
            save_string(key, content);
            return true;
        } else {
            return false;
        }
    }

    public String get_string(String key) {
        if (is_empty()) {
            return null;
        }
        return str_ops.get(key);
    }

    public void del_string(String uid) {
        try {
            if (StrUtil.isNotEmpty(uid)) {
                if (!Objects.isNull(str_temp) && str_temp.hasKey(uid)) {
                    str_temp.delete(uid);
                }
            }
        } catch (NullPointerException e) {
            Console.error("删除str key 失败");
        } finally {
            set_filter();
        }

    }

    /**
     * 保存hash 到缓存
     *
     * @param k  key
     * @param mk map key
     * @param mv map value
     */
    public void save_hash(String k, Object mk, Object mv) {
        if (tool.noEmpty(k, mk, mv, kv_ops)) {
            kv_ops.put(k, mk, mv);
        }
        set_filter();
    }

    /**
     * 保存一个map 对象到缓存
     *
     * @param k   key
     * @param map map对象
     */
    public void save_hash(String k, Map<Object, Object> map) {
        if (tool.noEmpty(k, map, kv_ops)) {
            kv_ops.putAll(k, map);
        }
        set_filter();
    }

    /**
     * 获取map
     *
     * @param k  key
     * @param mk map key
     * @return Object 对象
     */
    public Object get_map(String k, Object mk) {
        if (tool.noEmpty(k, mk, kv_ops) && redisTemplate.hasKey(k) && filter_key(k)) {
            return kv_ops.get(k, mk);
        } else {
            return null;
        }
    }

    // 过滤器 防止缓存穿透
    public boolean filter_key(String key) {
        return filter.contains(key);
    }

    private void set_filter() {
        Set<String> all_keys = str_temp.keys("*");// 获取所有存在的key
        all_keys.forEach(key -> {
            if (!filter_key(key)) {
                filter.add(key);
            }
        });
    }
}
